package P3;

import java.net.InetSocketAddress;
import java.net.UnknownHostException;

import NIOCommunication.NIOProcessor;
import NIOCommunication.NIOProcessorCloseContextCommand;
import NIOCommunication.NIOSocketContext;

public class PeerGathererContext extends NIOSocketContext
{
	private Worker mWorker;
	private String mPartialReply = "";
        private long mPeer;
	
	public PeerGathererContext(Worker worker, NIOProcessor processor, InetSocketAddress address)
	{
		super(processor, address);
		mWorker = worker;
                //System.out.println("Trying to get peers from " + address.getHostName());
		GetPeers();
	}
        
	public PeerGathererContext(Worker worker, NIOProcessor processor, InetSocketAddress address, long peer)
	{
		super(processor, address);
		mWorker = worker;
                //System.out.println("Trying to get peers from " + address.getHostName());
                mPeer = peer;
		GetPeers();
	}
	
	public PeerGathererContext(Worker worker, NIOProcessor processor) throws UnknownHostException
	{
		super(processor);
		mWorker = worker;
		GetPeers();
	}
	
	@Override
	public void OnReadData(byte[] data)
	{
		mPartialReply = mPartialReply + new String(data);
		 
		//System.out.println("Recieved the following:\n\n" + mPartialReply);
		
		if(mPartialReply.endsWith("\r\n\r\n"))
		{
			//System.out.println("Finished reading all of the data. Shutting down...");
			mNIOProcessor.QueueCommand(new NIOProcessorCloseContextCommand(this));
			ParseReply();
		}
	}
	
	public void ParseReply()
	{
            //System.out.println(mPartialReply);
            
            CrawlResult result = new CrawlResult();
            result.Address = mSocketChannel.socket().getInetAddress().getHostAddress() + ":" + mSocketChannel.socket().getPort();
            //result.HostName = "Fake host name";//mSocketChannel.socket().getInetAddress().getHostName();
            result.Status = "Gnutella Error"; // in case crawling fails
            
		String[] lines = mPartialReply.split("\r\n");
		for(int i = 0; i < lines.length; ++i)
		{
			String line = lines[i];
			if(line.startsWith("GNUTELLA/"))
			{
				line = line.substring(9);
				line = line.substring(0, line.indexOf(" "));
                                result.Status = "Peers Crawled";
				//System.out.println("Protocol = " + Float.parseFloat(line));
			}
			else if(line.startsWith("User-Agent: "))
			{
                            line = line.substring(12);
				//System.out.println("Agent = " + line);
                            result.Agent = line;
                                result.Status = "Peers Crawled";
			}
			else if(line.startsWith("Peers: "))
			{
				line = line.substring(7);
                                result.Peers = line;
                                result.Status = "Peers Crawled";
                                
				/*if(line.trim().length() == 0)
				{
					//System.out.println("Found no peers");
				}
				else
				{
					String[] peers = line.split(",");
					//System.out.println("Found " + peers.length + " new peers");

					//for(int j = 0; j < peers.length; ++j)
					//{
						//System.out.println("  Peer " + j + ": " + peers[j]);
					//}
					
					// TODO: fix
					mWorker.OnNewPeers(null, peers, true);
				}
                                 */
			}
			else if(line.startsWith("Leaves: "))
			{
				line = line.substring(8);
                                result.Leaves = line;
                                result.Status = "Peers Crawled";
				/*if(line.trim().length() == 0)
				{
					//System.out.println("Found no leaves");
				}
				else
				{
					String[] leaves = line.split(",");
					//System.out.println("Found " + leaves.length + " new leaves");
				
					//for(int j = 0; j < leaves.length; ++j)
					//{
						//System.out.println("  Leave " + j + ": " + leaves[j]);
					//}

					// TODO: fix
					mWorker.OnNewPeers(null, leaves, true);
				}*/
			}
			
			//System.out.println("Line " + i + ": " + lines[i]);
		}
		//System.out.println("We have crawled this many peers: " + (++numCrawled));
		
                mWorker.OnPeersGathered(result);
		mNIOProcessor.QueueCommand(new NIOProcessorCloseContextCommand(this));
	}
	static int numCrawled = 0;
	public void GetPeers()
	{
        StringBuffer request = new StringBuffer();
        request.append("GNUTELLA CONNECT/0.6\r\n" +
                        "User-Agent: UBCECE (carwl)\r\n" +
                        "Query-Routing: 0.2\r\n"+
                        "X-Ultrapeer: False\r\n"+
                        "Crawler: 0.1\r\n" +
                        "\r\n");
   
        byte[] bytes = request.toString().getBytes();
        WriteData(bytes);
        //System.out.println("Wrote " + request.toString());
	}

	@Override
	public void Close()
	{
		super.Close();
		mWorker.OnCrawlerClosed();
	}
        
        @Override
        public void OnChannelClosed(NIOSocketContext context)
        {
            if(context.mTCPError)
            {
                CrawlResult result = new CrawlResult();
                result.Address = AddressConverter.GetString(mPeer);
                result.Status = "TCP Error";
            
                mWorker.OnFilesGathered(result);
            }
        }
        
        @Override
        public void OnTimeout()
        {
            CrawlResult result = new CrawlResult();
            result.Address = AddressConverter.GetString(mPeer);
            result.Status = "Connection timed out";
            
            mWorker.OnFilesGathered(result);
            mWorker.OnCrawlerTimedOut();
        }
}
